package com.winning.gjhlht.ihe.cdaService.service;

import com.cownew.ctk.common.RandomGUID;
import com.framework.helper.ServerSQLExecutorUtils;
import com.framework.server.manager.SQLConfigLoader;
import com.winning.common.Constans;
import com.winning.common.data.service.PlatBasicDataService;
import com.winning.common.tools.SQLTool;
import com.winning.core.job.BaseJob;
import com.winning.gjhlht.bean.InterfaceConfigBean;
import com.winning.gjhlht.ihe.cdaService.service.IBaseCDACreaterServiceInter;
import com.winning.gjhlht.ihe.common.IHEConstans;
import com.winning.gjhlht.ihe.job.thread.HLHTCreateCDARequestTask;
import com.winning.gjhlht.ihe.job.thread.IHECreateCDARequestTask;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.UnsupportedEncodingException;
import java.util.*;

/**
 * 创建CDA文档接口
 *
 * @author z_dd@winning.com.cn
 * @date 2019/2/27 16:58
 */
@Component
public class CdaDocumentInterface {
    private static Logger LOGGER = Logger.getLogger(Constans.LOG4J_PBS_LOGGER_ID);

    @Autowired
    public IBaseCDACreaterServiceInter baseCDACreaterService = null;
    @Autowired
    public PlatBasicDataService platBasicDataService = null;

    //数据源
    private static String dbDataSourceID = "Default_SQL_Dev";

    //增量更新表的标识前缀
    private static String serviceID = "CDA_BUFFER_01";


    /**
     * 生成CDA文档方法
     *
     * @param
     * @author z_dd@winning.com.cn
     * @date 2019/2/27 17:04
     */
    public void createCDATest(InterfaceConfigBean bean) {

        String queryGRZCJGSQL = SQLConfigLoader.getSQLByID(bean.getSQLByID());
        //1、从基础SQL中按照规则提取增量更新表名称，规则为TABLENAME_TBRQ，TBRQ是平台所有表必须有的字段
        HashMap<String, String> tableNameMap = SQLTool.getTableNameFromSQL(queryGRZCJGSQL);
        //2、获取业务库中保存的增量更新时间
        HashMap<String, String> tableValueMapFromDB = platBasicDataService.getTableIncreaseTimeMapFromDB();
        //3、增加增量流程的SQL
        String increaseSQLStr = SQLTool.createIncreaseSQL(serviceID, queryGRZCJGSQL, tableNameMap, tableValueMapFromDB);

        LOGGER.info("-->基础配置SQL为:[" + queryGRZCJGSQL + "]");

        LOGGER.info("-->增量更新处理后SQL为:[" + increaseSQLStr + "]");

        //4、统计SQL
        String countSQL = "SELECT " + "COUNT(1) AS " + BaseJob.COLUMN_COUNT + " FROM (" + increaseSQLStr + ") A";

        LOGGER.info("-->查询总数SQL为:[" + countSQL + "]");

        //总共查询出多少条数据量, 多数据源支持
        int totalDataCount = platBasicDataService.getPlatBasicDataCountHandler(countSQL, BaseJob.COLUMN_COUNT,
                dbDataSourceID);

        LOGGER.info("-->总数据量为:[" + totalDataCount + "]");


        //【2】、计算需要创建的线程数量
        int jobsNumber = 1;

        //一批次上传的数据量，也可理解为一页的数量
        int perSize = 2500;

        jobsNumber = totalDataCount / perSize;

        if (totalDataCount % perSize > 0) {
            jobsNumber += 1;
        }

        //批次分页页码
        int pageIndexNum = 0;

        //分批次执行上传
        for (int pcStartIndex = 0; pcStartIndex < jobsNumber; pcStartIndex++) {
            //每次都会在sql中增加最新的增量时间，每次都应该是从第一页开始
            List<Map<String, Object>> registrationRequestInfoDataList = platBasicDataService
                    .getPlatBasicDataByIncreaseTimeHandler(dbDataSourceID, serviceID, queryGRZCJGSQL, pageIndexNum,
                            perSize);

            if (registrationRequestInfoDataList == null || registrationRequestInfoDataList.size() == 0) {
                LOGGER.info("--> 没有数据");
            } else {
                int result = createIHERegistrationRequestTaskHandler1(registrationRequestInfoDataList, queryGRZCJGSQL, bean);
                pageIndexNum += 1;
                if (result > 0) {
                    /* 返回1，是因为，业务发生时间和数据库记录的增量时间相同，表示一个时间段内发生的数据量太大（同一时间内的数据量远大于一页）
                     * 第二批次查询数据就必须向后翻一页。
                     */
                    pageIndexNum += 1;
                } else {
                    //返回0，是因为，SQL每次都会做增量时间操作，每次的查询都是根据最新的时间筛选，所以每次的查询结果集都应该是从第一页开始。
                    pageIndexNum = 0;
                }
            }

        }

    }
    private int createIHERegistrationRequestTaskHandler1(List<Map<String, Object>> registrationRequestInfoDataList,
                                                         String basicSQL, InterfaceConfigBean bean) {
        //单个线程可执行的上传数据量
        int baseNumber = 100;

        //计算处理所有数据需要启动的线程数量
        int totalNumber = registrationRequestInfoDataList.size();
        int threadNumber = totalNumber / baseNumber;

        if (totalNumber % baseNumber > 0) {
            threadNumber += 1;
        }

        List<HLHTCreateCDARequestTask> dataSetSubmitThreadList = new ArrayList<>();

        //创建提交数据线程
        for (int j = 0; j < threadNumber; j++) {
            int fromIndex = j * baseNumber;
            int toIndex = (j + 1) * baseNumber;

            List<Map<String, Object>> tempRowListValue = new ArrayList<Map<String, Object>>();

            //截取一段数据
            for (int index = fromIndex; index < toIndex; index++) {
                if (index < registrationRequestInfoDataList.size()) {
                    tempRowListValue.add(registrationRequestInfoDataList.get(index));
                }
            }

            Timer timer = new Timer();


            HLHTCreateCDARequestTask dataSetSubmitThread = new HLHTCreateCDARequestTask(tempRowListValue, baseCDACreaterService, bean);
            timer.schedule(dataSetSubmitThread, 0);
            //保存所有的线程
            dataSetSubmitThreadList.add(dataSetSubmitThread);
        }

        //********************* 2、检查所有子线程的执行结果，一批提交接口线程数据执行结果 *********************
        boolean isAllOver = false;

        //当前线程已经变换为监控线程，持续判断子线程的执行结果，如果所有子线程全部执行完毕，表示当前job执行结束。可做更新增量时间操作
        while (!isAllOver) {
            for (int threadIndex = 0; dataSetSubmitThreadList != null
                    && threadIndex < dataSetSubmitThreadList.size(); threadIndex++) {
                HLHTCreateCDARequestTask iheRegistrationRequestTask = dataSetSubmitThreadList.get(threadIndex);

                if (!iheRegistrationRequestTask.isOver()) {
                    isAllOver = false;
                    break;
                }

                iheRegistrationRequestTask.cancel();
                iheRegistrationRequestTask = null;

                isAllOver = true;

            }

            try {
                //持续监控
                Thread.sleep(10);
            } catch (InterruptedException e) {
                //打印异常堆栈信息
                LOGGER.error(e, e.fillInStackTrace());
                e.printStackTrace();
            }
        }
        //********************* 3、所有线程执行完毕后，更新增量时间 *********************
        int pageIndexNum = platBasicDataService.saveMaxTBRQToDB("xj", serviceID, "", basicSQL, dbDataSourceID);
        return pageIndexNum;

    }

    // 16进制转10进制
    public static int HexToInt(String strHex) {
        int nResult = 0;
        if (!IsHex(strHex)) {
            return nResult;
        }
        String str = strHex.toUpperCase();
        if (str.length() > 2) {
            if (str.charAt(0) == '0' && str.charAt(1) == 'X') {
                str = str.substring(2);
            }
        }
        int nLen = str.length();
        for (int i = 0; i < nLen; ++i) {
            char ch = str.charAt(nLen - i - 1);
            try {
                nResult += (GetHex(ch) * GetPower(16, i));
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return nResult;
    }

    // 判断是否是16进制数
    public static boolean IsHex(String strHex) {
        int i = 0;
        if (strHex.length() > 2) {
            if (strHex.charAt(0) == '0'
                    && (strHex.charAt(1) == 'X' || strHex.charAt(1) == 'x')) {
                i = 2;
            }
        }
        for (; i < strHex.length(); ++i) {
            char ch = strHex.charAt(i);
            if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F')
                    || (ch >= 'a' && ch <= 'f')) {
                continue;
            }
            return false;
        }
        return true;
    }

    // 计算16进制对应的数值
    public static int GetHex(char ch) throws Exception {
        if (ch >= '0' && ch <= '9')
            return (int) (ch - '0');
        if (ch >= 'a' && ch <= 'f')
            return (int) (ch - 'a' + 10);
        if (ch >= 'A' && ch <= 'F')
            return (int) (ch - 'A' + 10);
        throw new Exception("error param");
    }

    // 计算幂
    public static int GetPower(int nValue, int nCount) throws Exception {
        if (nCount < 0) {
            throw new Exception("nCount can't small than 1!");
        }
        if (nCount == 0) {
            return 1;
        }
        int nSum = 1;
        for (int i = 0; i < nCount; ++i) {
            nSum = nSum * nValue;
        }
        return nSum;
    }

    public static String getBASE64(String cdaContentValue) {

        try {
            String base64Str = "";

            if (cdaContentValue == null) {
                return null;
            }

            try {

                base64Str = (new sun.misc.BASE64Encoder()).encode(cdaContentValue.getBytes("UTF-8")).replace("\n", "").replace("\r", "");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }

            return base64Str;
        } catch (Exception e) {
            LOGGER.error(e, e.fillInStackTrace());
        }

        return null;
    }

    private int saveCDADOCBUFFER(HashMap<String, Object> map) {
        try {
            //拼接插入SQL语句
            //填充信息
            Object[] params = new Object[map.size()];

            String insertSQL = "INSERT INTO IHE_CDA_DOC_BUFFER (";

            //参数个数标记
            int index = 0;

            //根据个人信息map表动态填充insert语句
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                String key = entry.getKey();
                Object value = entry.getValue();

                insertSQL += key + ",";

                params[index] = value;

                index++;

            }

//			//去除最后一个  ，符号
//			insertSQL = insertSQL.substring(0,insertSQL.length()-1);

            //添加创建时间createTime
            insertSQL += "CreateTime ";

            insertSQL += ") VALUES (";

            for (int i = 0; i < index; i++) {
                insertSQL += "?,";
            }

//			//去除最后一个  ，符号
//			insertSQL = insertSQL.substring(0,insertSQL.length()-1);

            //判断是否有OR
            if (dbDataSourceID.indexOf(Constans.DATA_SOURCE_ORACLE_TAG) > -1) {
                insertSQL += "sysdate ";
            } else {
                insertSQL += "getdate() ";
            }
            //添加创建时间createTime


            insertSQL += ")";

            LOGGER.info("-->新增SQL语句" + insertSQL);
            LOGGER.info("-->参数:" + params.toString());

            ServerSQLExecutorUtils.execute(insertSQL, params, dbDataSourceID);

            LOGGER.info("-->新增成功");

            return 1;
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error(e.getMessage());
        }

        return -1;

    }

    private HashMap<String, Object> queryGRJBXX(String grjbxxbsh) {
        try {

            String queryGRJBXXSQL = SQLConfigLoader.getSQLByID("IHE_QUERY_GRJBXX_FOR_INSERT");

            //LOGGER.info("-->查询个人信息语句SQL = " + queryGRJBXXSQL);

            List<HashMap<String, Object>> jbxxList = ServerSQLExecutorUtils.executeQueryOtherDB(queryGRJBXXSQL, new Object[]{grjbxxbsh}, dbDataSourceID);

            if (jbxxList != null && jbxxList.size() > 0) {

                return jbxxList.get(0);
            }

        } catch (Exception e) {
            LOGGER.error(e.getMessage());
            e.printStackTrace();
        }

        return null;
    }
    /*********************删下**************************/


    /**
     * 创建线程批量生成CDA文档
     * 方法名称: createIHERegistrationRequestTaskHandler
     *
     * @param
     * @return int  返回类型说明<br/>
     * @throws <br/>
     * @author zq@winning.com.cn<br/>
     * 创建时间：2017-1-14/下午12:06:44<br/>
     */
    private int createIHERegistrationRequestTaskHandler(List<Map<String, Object>> registrationRequestInfoDataList,
                                                        String basicSQL) {

        //单个线程可执行的上传数据量
        int baseNumber = 100;

        //计算处理所有数据需要启动的线程数量
        int totalNumber = registrationRequestInfoDataList.size();
        int threadNumber = totalNumber / baseNumber;

        if (totalNumber % baseNumber > 0) {
            threadNumber += 1;
        }

        List<IHECreateCDARequestTask> dataSetSubmitThreadList = new ArrayList<IHECreateCDARequestTask>();

        //创建提交数据线程
        for (int j = 0; j < threadNumber; j++) {
            int fromIndex = j * baseNumber;
            int toIndex = (j + 1) * baseNumber;

            List<Map<String, Object>> tempRowListValue = new ArrayList<Map<String, Object>>();

            //截取一段数据
            for (int index = fromIndex; index < toIndex; index++) {
                if (index < registrationRequestInfoDataList.size()) {
                    tempRowListValue.add(registrationRequestInfoDataList.get(index));
                }
            }

            Timer timer = new Timer();

            //创建执行上传数据接口的线程
            IHECreateCDARequestTask dataSetSubmitThread = new IHECreateCDARequestTask(tempRowListValue,
                    baseCDACreaterService, dbDataSourceID);
            timer.schedule(dataSetSubmitThread, 0);

            //保存所有的线程
            dataSetSubmitThreadList.add(dataSetSubmitThread);

        }

        //********************* 2、检查所有子线程的执行结果，一批提交接口线程数据执行结果 *********************
        boolean isAllOver = false;

        //当前线程已经变换为监控线程，持续判断子线程的执行结果，如果所有子线程全部执行完毕，表示当前job执行结束。可做更新增量时间操作
        while (!isAllOver) {
            for (int threadIndex = 0; dataSetSubmitThreadList != null
                    && threadIndex < dataSetSubmitThreadList.size(); threadIndex++) {
                IHECreateCDARequestTask iheRegistrationRequestTask = dataSetSubmitThreadList.get(threadIndex);

                if (!iheRegistrationRequestTask.isOver()) {
                    isAllOver = false;
                    break;
                }

                iheRegistrationRequestTask.cancel();
                iheRegistrationRequestTask = null;

                isAllOver = true;

            }

            try {
                //持续监控
                Thread.sleep(10);
            } catch (InterruptedException e) {
                //打印异常堆栈信息
                LOGGER.error(e, e.fillInStackTrace());
                e.printStackTrace();
            }
        }
        //********************* 3、所有线程执行完毕后，更新增量时间 *********************
        int pageIndexNum = platBasicDataService.saveMaxTBRQToDB("xj", serviceID, "", basicSQL, dbDataSourceID);
        return pageIndexNum;

    }
}
